package com.catsic.base.utils;

import java.security.Key;
import java.security.SecureRandom;
import java.util.UUID;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

import com.catsic.base.exception.CatsicException;
import com.catsic.base.exception.CatsicExceptionCode;

public class DESUtil {
	
    /**
     * 算法名称 
     */
    public static final String KEY_ALGORITHM = "DES";
    
    /**
     * 加密、解密KEY
     */
    public static final String KEY = "1A2B3C4D5E6F7G8H";
    
    /**
     * 算法名称/加密模式/填充方式 
     * DES共有四种工作模式-->>ECB：电子密码本模式、CBC：加密分组链接模式、CFB：加密反馈模式、OFB：输出反馈模式
     */
    public static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding";

    /**
     * 生成密钥key对象
     * @param KeyStr 密钥字符串 
     * @return 密钥对象 
     * @throws InvalidKeyException   
     * @throws NoSuchAlgorithmException   
     * @throws InvalidKeySpecException   
     * @throws Exception 
     */
    private static SecretKey keyGenerator(String keyStr){
    	try{
            byte input[] = HexString2Bytes(keyStr);
            DESKeySpec desKey = new DESKeySpec(input);
            /**
             * 创建一个密匙工厂，然后用它把DESKeySpec转换成
             */
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            return securekey;
		} catch (Exception e) {
			throw new CatsicException(CatsicExceptionCode.生成密钥错误);
		}
    }

    private static int parse(char c) {
        if (c >= 'a') return (c - 'a' + 10) & 0x0f;
        if (c >= 'A') return (c - 'A' + 10) & 0x0f;
        return (c - '0') & 0x0f;
    }

    /*
     * 从十六进制字符串到字节数组转换 
     */
    public static byte[] HexString2Bytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = hexstr.charAt(j++);
            char c1 = hexstr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }

    /** 
     * 加密数据
     * @param data 待加密数据
     * @param key 密钥
     * @return 加密后的数据 
     */
    public static String encrypt_(String data, String key) {
    	try {
    		Key deskey = keyGenerator(key);
            /**
             * 实例化Cipher对象，它用于完成实际的加密操作
             */
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            SecureRandom random = new SecureRandom();
            /**
             * 初始化Cipher对象，设置为加密模式
             */
            cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
            byte[] results = cipher.doFinal(data.getBytes());
            /**
             * 该部分是为了与加解密在线测试网站（http://tripledes.online-domain-tools.com/）的十六进制结果进行核对
             */
            for (int i = 0; i < results.length; i++) {
                System.out.print(results[i] + " ");
            }
            /**
             * 执行加密操作。加密后的结果通常都会用Base64编码进行传输 
             */
            return new String(Base64.encodeBase64(results));
		} catch (Exception e) {
			throw new CatsicException(CatsicExceptionCode.加密错误);
		}
    }

    /** 
     * 解密数据 
     * @param data 待解密数据 
     * @param key 密钥 
     * @return 解密后的数据 
     */
    public static String decrypt_(String data, String key) {
    	try{
    		Key deskey = keyGenerator(key);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            /**
             * 初始化Cipher对象，设置为解密模式
             */
            cipher.init(Cipher.DECRYPT_MODE, deskey);
            /**
             * 执行解密操作
             */
            return new String(cipher.doFinal(Base64.decodeBase64(data.getBytes())));
		} catch (Exception e) {
			throw new CatsicException(CatsicExceptionCode.解密错误);
		}
        
    }

    /**
     * 加密
     * 
     * @param content
     *            待加密内容
     * @param key
     *            加密的密钥
     * @return
     */
    public static String encrypt(String content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(key.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            byte[] byteRresult = cipher.doFinal(byteContent);
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteRresult.length; i++) {
                String hex = Integer.toHexString(byteRresult[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }
            return sb.toString();
        } catch (Exception e) {
			throw new CatsicException(CatsicExceptionCode.加密错误);
		}
    }
 
    /**
     * 解密
     * 
     * @param content
     *            待解密内容
     * @param key
     *            解密的密钥
     * @return
     */
    public static String decrypt(String content, String key) {
        if (content.length() < 1)
            return null;
        byte[] byteRresult = new byte[content.length() / 2];
        for (int i = 0; i < content.length() / 2; i++) {
            int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
            byteRresult[i] = (byte) (high * 16 + low);
        }
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(key.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] result = cipher.doFinal(byteRresult);
            return new String(result);
        } catch (Exception e) {
			throw new CatsicException(CatsicExceptionCode.解密错误);
		}
    }
    
    public static void main(String[] args){
        String source = "原文||||";
        System.out.println(source.length());
        System.out.println("原文: " + source);
        String key = UUID.randomUUID().toString().substring(0, 16);
        String encryptData = encrypt(source, key);
        System.out.println("加密后: " + encryptData);
        String decryptData = decrypt(encryptData, key);
        System.out.println("解密后: " + decryptData);
    }
}